#ifndef _MAPOBJECT_TEST_H_
#define _MAPOBJECT_TEST_H_

#include "MapObject.h"
#include "Monster.h"

#include "FloorNamable.h"
#include "FloorRepresentable.h"
#include "FloorMovable.h"
#include "FloorLiving.h"
#include "FloorSolid.h"
#include "FloorDoesDamage.h"
#include "FloorHasMonster.h"

#include "mock_INamable.h"
#include "mock_IRepresentable.h"
#include "mock_ILiving.h"
#include "mock_IMovable.h"
#include "mock_ISolid.h"
#include "mock_IDoesDamage.h"
#include "mock_IHasMonster.h"

#include "gmock/gmock.h"
#include "gtest/gtest.h"

using ::testing::AtLeast;
using ::testing::Return;
using ::testing::ReturnRef;

/**
 * Test for getting the map object name.
 */
TEST(MapObject_INamableMock, nameGetting)
{
  const std::string n = "Mock Name";

  INamableMock namable_mock;

  EXPECT_CALL(namable_mock, getName())
    .Times(AtLeast(1))
    .WillOnce(ReturnRef(n));

  FloorRepresentable r;
  FloorMovable m;
  FloorLiving l;
  FloorSolid s;
  FloorDoesDamage d;
  FloorHasMonster h;

  MapObject mapObject(&namable_mock, &r, &m, &l, &s, &d, &h);

  EXPECT_TRUE(n == mapObject.getName());
}

/**
 * Test for getting the representation of the map object.
 */
TEST(MapObject_IRepresentableMock, gettingRepresentation)
{
  const char rep = 'R';

  IRepresentableMock representable_mock;

  EXPECT_CALL(representable_mock, getAsciiRepresentation())
    .Times(AtLeast(1))
    .WillOnce(Return(rep));

  FloorNamable n;
  FloorMovable m;
  FloorLiving l;
  FloorSolid s;
  FloorDoesDamage d;
  FloorHasMonster h;

  MapObject mapObject(&n, &representable_mock, &m, &l, &s, &d, &h);

  EXPECT_TRUE(rep == mapObject.getAsciiRepresentation());
}

/**
 * Test for getting health of the map object.
 */
TEST(MapObject_ILivingMock, gettingHealth)
{
  const int healthGetter = 10;
  ILivingMock living_mock;

  EXPECT_CALL(living_mock, getHealth())
    .Times(AtLeast(1))
    .WillOnce(Return(healthGetter));

  FloorNamable n;
  FloorRepresentable r;
  FloorMovable m;
  FloorSolid s;
  FloorDoesDamage d;
  FloorHasMonster h;

  MapObject mapObject(&n, &r, &m, &living_mock, &s, &d, &h);

  EXPECT_TRUE(healthGetter == mapObject.getHealth());
}

/**
 * Test for healing the map object (probably won't be used).
 */
TEST(MapObject_ILivingMock, healing)
{
  const int healer = 10;
  ILivingMock living_mock;

  EXPECT_CALL(living_mock, heal(healer))
    .Times(AtLeast(1));

  FloorNamable n;
  FloorRepresentable r;
  FloorMovable m;
  FloorSolid s;
  FloorDoesDamage d;
  FloorHasMonster h;

  MapObject mapObject(&n, &r, &m, &living_mock, &s, &d, &h);

  mapObject.heal(healer);
}

/**
 * Test for hurting the map object.
 */
TEST(MapObject_ILivingMock, hurting)
{
  const int hurter = 10;
  ILivingMock living_mock;

  EXPECT_CALL(living_mock, hurt(hurter))
    .Times(AtLeast(1));

  FloorNamable n;
  FloorRepresentable r;
  FloorMovable m;
  FloorSolid s;
  FloorDoesDamage d;
  FloorHasMonster h;

  MapObject mapObject(&n, &r, &m, &living_mock, &s, &d, &h);

  mapObject.hurt(hurter);
}

/**
 * Test for getting the object solidness.
 */
TEST(MapObject_ISolidMock, isSolid)
{
  ISolidMock solid_mock;

  EXPECT_CALL(solid_mock, isSolid())
    .Times(AtLeast(1))
    .WillOnce(Return(true));

  FloorNamable n;
  FloorRepresentable r;
  FloorLiving l;
  FloorMovable m;
  FloorDoesDamage d;
  FloorHasMonster h;

  MapObject mapObject(&n, &r, &m, &l, &solid_mock, &d, &h);

  EXPECT_TRUE(true == mapObject.isSolid());
}

/**
 * Test for setting a monster associated with the map object.
 */
TEST(MapObject_IHasMonsterMock, setMonster)
{
  IHasMonsterMock monster_mock;

  RegularSoldierNamable mn;
  RegularSoldierRepresentable mr;
  RegularSoldierMovable mm;
  RegularSoldierLiving ml;

  Monster monty(&mn, &mr, &mm, &ml);

  EXPECT_CALL(monster_mock, setMonster(&monty))
    .Times(AtLeast(1));

  FloorNamable n;
  FloorRepresentable r;
  FloorLiving l;
  FloorMovable m;
  FloorSolid s;
  FloorDoesDamage d;

  MapObject mapObject(&n, &r, &m, &l, &s, &d, &monster_mock);

  mapObject.setMonster(&monty);
}

/**
 * Test for getting a monster associated with the map object.
 */
TEST(MapObject_IHasMonsterMock, getMonster)
{
  IHasMonsterMock monster_mock;

  RegularSoldierNamable mn;
  RegularSoldierRepresentable mr;
  RegularSoldierMovable mm;
  RegularSoldierLiving ml;

  Monster monty(&mn, &mr, &mm, &ml);

  EXPECT_CALL(monster_mock, getMonster())
    .Times(AtLeast(1))
    .WillOnce(Return(&monty));

  FloorNamable n;
  FloorRepresentable r;
  FloorLiving l;
  FloorMovable m;
  FloorSolid s;
  FloorDoesDamage d;

  MapObject mapObject(&n, &r, &m, &l, &s, &d, &monster_mock);

  EXPECT_TRUE(&monty == mapObject.getMonster());
}

/**
 * Test the damage doer by the map object.
 */
TEST(MapObject_IDoDamage, doDamage)
{
  IDoesDamageMock damage_mock;
  const int damage_was_done = 0x777;

  EXPECT_CALL(damage_mock, doDamage())
    .Times(AtLeast(1))
    .WillOnce(Return(damage_was_done));

  FloorNamable n;
  FloorRepresentable r;
  FloorLiving l;
  FloorMovable m;
  FloorSolid s;
  FloorHasMonster h;

  MapObject mapObject(&n, &r, &m, &l, &s, &damage_mock, &h);

  EXPECT_TRUE(damage_was_done == mapObject.doDamage());
}

/**
 * Test for getting the map object position.
 */
TEST(MapObject_IMovable, getPosition)
{
  IMovableMock movable_mock;
  IMovable::movableVector v;
  v.push_back(0x666);
  v.push_back(0x777);

  EXPECT_CALL(movable_mock, getPosition())
    .Times(AtLeast(1))
    .WillOnce(ReturnRef(v));

  FloorNamable n;
  FloorRepresentable r;
  FloorLiving l;
  FloorDoesDamage d;
  FloorSolid s;
  FloorHasMonster h;

  MapObject mapObject(&n, &r, &movable_mock, &l, &s, &d, &h);

  EXPECT_TRUE(v == mapObject.getPosition());
}

/**
 * Test for setting the map object position.
 */
TEST(MapObject_IMovable, setPosition)
{
  IMovableMock movable_mock;
  IMovable::movableVector v;
  v.push_back(0x666);
  v.push_back(0x777);

  EXPECT_CALL(movable_mock, setPosition(v))
    .Times(AtLeast(1));

  FloorNamable n;
  FloorRepresentable r;
  FloorLiving l;
  FloorDoesDamage d;
  FloorSolid s;
  FloorHasMonster h;

  MapObject mapObject(&n, &r, &movable_mock, &l, &s, &d, &h);

  mapObject.setPosition(v);
}

/**
 * Test for moving the map object.
 */
TEST(MapObject_IMovable, movePosition)
{
  IMovableMock movable_mock;
  IMovable::movableVector v;
  v.push_back(0x666);
  v.push_back(0x777);

  EXPECT_CALL(movable_mock, movePosition(v))
    .Times(AtLeast(1));

  FloorNamable n;
  FloorRepresentable r;
  FloorLiving l;
  FloorDoesDamage d;
  FloorSolid s;
  FloorHasMonster h;

  MapObject mapObject(&n, &r, &movable_mock, &l, &s, &d, &h);

  mapObject.movePosition(v);
}
#endif /* _MAPOBJECT_TEST_H_ */

